"""
审计日志服务
提供审计日志的创建和查询功能
"""
from motor.motor_asyncio import AsyncIOMotorDatabase
from datetime import datetime
from typing import Optional, List
from bson import ObjectId

from models.audit import (
    AuditLogCreate,
    AuditLogInDB,
    AuditLogOut,
    AuditLogQuery,
    AuditAction,
    AuditStatus,
    ResourceType
)


class AuditService:
    """审计服务"""
    
    def __init__(self, db: AsyncIOMotorDatabase):
        self.db = db
        self.collection = db.audit_logs
    
    async def create_audit_log(
        self,
        user_id: str,
        action: AuditAction,
        resource_type: ResourceType,
        status: AuditStatus,
        request_id: str,
        resource_id: Optional[str] = None,
        ip_address: Optional[str] = None,
        user_agent: Optional[str] = None,
        details: Optional[dict] = None,
        error_message: Optional[str] = None
    ) -> str:
        """
        创建审计日志
        
        Args:
            user_id: 用户ID
            action: 操作动作
            resource_type: 资源类型
            status: 操作状态
            request_id: 请求ID
            resource_id: 资源ID（可选）
            ip_address: IP地址（可选）
            user_agent: 用户代理（可选）
            details: 详细信息（可选）
            error_message: 错误信息（可选）
        
        Returns:
            str: 审计日志ID
        """
        audit_data = {
            "user_id": user_id,
            "action": action.value,
            "resource_type": resource_type.value,
            "resource_id": resource_id,
            "status": status.value,
            "request_id": request_id,
            "ip_address": ip_address,
            "user_agent": user_agent,
            "details": details or {},
            "error_message": error_message,
            "timestamp": datetime.utcnow()
        }
        
        result = await self.collection.insert_one(audit_data)
        return str(result.inserted_id)
    
    async def query_audit_logs(
        self,
        query: AuditLogQuery
    ) -> tuple[List[AuditLogOut], int]:
        """
        查询审计日志
        
        Args:
            query: 查询条件
        
        Returns:
            tuple: (审计日志列表, 总数)
        """
        # 构建查询条件
        filter_dict = {}
        
        if query.user_id:
            filter_dict["user_id"] = query.user_id
        
        if query.action:
            filter_dict["action"] = query.action.value
        
        if query.resource_type:
            filter_dict["resource_type"] = query.resource_type.value
        
        if query.resource_id:
            filter_dict["resource_id"] = query.resource_id
        
        if query.status:
            filter_dict["status"] = query.status.value
        
        if query.request_id:
            filter_dict["request_id"] = query.request_id
        
        # 时间范围查询
        if query.start_time or query.end_time:
            filter_dict["timestamp"] = {}
            if query.start_time:
                filter_dict["timestamp"]["$gte"] = query.start_time
            if query.end_time:
                filter_dict["timestamp"]["$lte"] = query.end_time
        
        # 查询总数
        total = await self.collection.count_documents(filter_dict)
        
        # 查询列表
        cursor = self.collection.find(filter_dict)\
            .sort("timestamp", -1)\
            .skip(query.skip)\
            .limit(query.limit)
        
        logs = await cursor.to_list(length=query.limit)
        
        # 转换数据格式
        result = []
        for log in logs:
            log["id"] = str(log.pop("_id"))
            result.append(AuditLogOut(**log))
        
        return result, total
    
    async def get_audit_log(self, log_id: str) -> Optional[AuditLogOut]:
        """
        获取单条审计日志
        
        Args:
            log_id: 日志ID
        
        Returns:
            AuditLogOut: 审计日志
        """
        if not ObjectId.is_valid(log_id):
            return None
        
        log = await self.collection.find_one({"_id": ObjectId(log_id)})
        
        if not log:
            return None
        
        log["id"] = str(log.pop("_id"))
        return AuditLogOut(**log)
    
    async def delete_old_logs(self, days: int = 90) -> int:
        """
        删除过期的审计日志
        
        Args:
            days: 保留天数（默认90天）
        
        Returns:
            int: 删除的日志数量
        """
        from datetime import timedelta
        
        cutoff_date = datetime.utcnow() - timedelta(days=days)
        
        result = await self.collection.delete_many({
            "timestamp": {"$lt": cutoff_date}
        })
        
        return result.deleted_count


# 便捷函数
async def log_audit(
    db: AsyncIOMotorDatabase,
    user_id: str,
    action: AuditAction,
    resource_type: ResourceType,
    status: AuditStatus,
    request_id: str,
    resource_id: Optional[str] = None,
    ip_address: Optional[str] = None,
    user_agent: Optional[str] = None,
    details: Optional[dict] = None,
    error_message: Optional[str] = None
) -> str:
    """
    快捷创建审计日志
    
    使用示例：
        await log_audit(
            db=db,
            user_id=current_user["id"],
            action=AuditAction.CREATE,
            resource_type=ResourceType.NOTE,
            status=AuditStatus.SUCCESS,
            request_id=request_id,
            resource_id=note_id,
            details={"title": note.title}
        )
    """
    audit_service = AuditService(db)
    return await audit_service.create_audit_log(
        user_id=user_id,
        action=action,
        resource_type=resource_type,
        status=status,
        request_id=request_id,
        resource_id=resource_id,
        ip_address=ip_address,
        user_agent=user_agent,
        details=details,
        error_message=error_message
    )

